package com.ruoyi.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.*;

public class WeChatUtils {

    //appid
    public static String weChatAppid = "wxe4eb4267e98b952a";

    //appsecret
    public static String weChatAppsecret ="9d7dbf01572eef6a82f60a078c7cd69e";

    //微信支付商户号
    public static String weChatPayMchId = "1645954599";

    //支付key
    public static String weChatPayKey = "J24XKnFavprVxNY6YvsRBLKCer34iokj";

    public static String weChatRedirectUri = "http://www.baidu.com";

    //支付回调地址
    public static String weChatPayNotifyUrl = "https://wechat.horgoscloud.cn/app/weChatPayNotify";

    public static String weChatAuthorizeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";

    public static String weChatAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";

    public static String weChatUserinfoUrl = "https://api.weixin.qq.com/sns/userinfo";

    public static String weChatPayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    public static String weChatPayOrderQueryUrl = "https://api.mch.weixin.qq.com/pay/orderquery";

    //private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final String SYMBOLS2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();


    /**
     * 获取微信Jsapi的accessToken
     */
    public static String getAccessToken() throws IOException{
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        url = url.replace("APPID",weChatAppid).replace("APPSECRET",weChatAppsecret);
        String result = WeChatHttpUtils.sendGet(url);
        JSONObject jsonObject = JSON.parseObject(result);
        String accessToken = jsonObject.getString("access_token");
        return accessToken;
    }

    /**
     *
     * @Title: getNonceStr
     * @Description: 生成随机字符串
     * @param @return
     * @return String    返回类型
     * @throws
     */
    public static String getNonceStr() {
        String currT = getCurrTime();
        String strT = currT.substring(8, currT.length());
        String strRandom = buildRandom(4) + "";
        return strT + strRandom;
    }



    /**
     *
     * @Title: buildRandom
     * @Description: 生成随机数
     * @param @param length
     * @param @return
     * @return int    返回类型
     * @throws
     */
    public static int buildRandom(int length) {
        int mm= 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            mm= mm* 10;
        }
        return (int) ((random * mm));
    }


    /**
     *
     * @Title: getCurrTime
     * @Description: 获取当前时间
     * @param @return
     * @return String    返回类型
     * @throws
     */
    public static String getCurrTime() {
        Date date = new Date();
        SimpleDateFormat of= new SimpleDateFormat("yyyyMMddHHmmss");
        String s = of.format(date);
        return s;
    }


    /**
     * 随机字符串
     * @return
     */
    public static String generateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
    }

    /**
     *
     * @Title: createSignBySha1
     * @Description: 生成签名
     * @param @param params
     * @param @return
     * @return String    返回类型
     * @throws
     */
    @SuppressWarnings("rawtypes")
    public static String createSignBySha1(SortedMap<Object, Object> params) {
        StringBuffer sb = new StringBuffer();
        Set es = params.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (v != null && !v.equals("")) {
                sb.append(k + "=" + v + "&");
            }
        }
        String result = sb.toString().substring(0, sb.toString().length()-1);
        return getSHA1(result);
    }
    /**
     *
     * @Title: getTimestamp
     * @Description: 获取时间戳(秒)
     * @param @return    参数
     * @return String    返回类型
     * @throws
     */
    public static String getTimestamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }


    /**
     *
     * @Title: getSHA1
     * @Description: SHA1签名生成
     * @param @param str
     * @param @return    参数
     * @return String    返回类型
     * @throws
     */
    public static String getSHA1(String str){
        StringBuffer hexstr = new StringBuffer();
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return hexstr.toString();
    }

    /**
     *
     * @Title: getJsapiTicket
     * @Description: 获取JsapiTicket
     * @param @param access_token
     * @param @return
     * @return String    返回类型
     * @throws
     */
    public static String getJsapiTicket(String access_token)  throws IOException{
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi".replace("ACCESS_TOKEN",access_token);
        String result = WeChatHttpUtils.sendGet(url);
        JSONObject jsonObject = JSON.parseObject(result);
        String ticket= jsonObject.getString("ticket");
        return ticket;
    }


    public static String createLinkString(Map<String, String> params){
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
//          try {
//              value = URLEncoder.encode(value, "UTF-8");
//          }catch (Exception e){
//              e.printStackTrace();
//          }
            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }

    public static String generateSignature(final Map<String, String> data, String key, String signType) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals("sign")) {
                continue;
            }
            if (data.get(k).trim().length() > 0) {
                //参数值为空，则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
            }

        }
        sb.append("key=").append(key);
        if ("MD5".equals(signType)) {
            return MD5(sb.toString()).toUpperCase();
        }else if ("HMACSHA256".equals(signType)) {
            return HMACSHA256(sb.toString(), key);
        }else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }

    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    public static String mapToXml(Map<String, String> map) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set<String> set = map.keySet();
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            String key = it.next();
            sb.append("<" + key + ">").append(map.get(key)).append("</" + key + ">");
        }
        sb.append("</xml>");
        return sb.toString();

    }

    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<String, String>();
            DocumentBuilder documentBuilder = newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
            getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
            throw ex;
        }

    }

    public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        documentBuilderFactory.setXIncludeAware(false);
        documentBuilderFactory.setExpandEntityReferences(false);

        return documentBuilderFactory.newDocumentBuilder();
    }


    public static Document newDocument() throws ParserConfigurationException {
        return newDocumentBuilder().newDocument();
    }

    public static Logger getLogger() {
        Logger logger = LoggerFactory.getLogger("wxpay java sdk");
        return logger;
    }

    /**
     * @TODO :
     * @AUTH : linfeng
     * @DATE : 2020年10月19日 上午9:34:49
     * @return_type : String
     * @return
     */
    public static String generateNonceStr5() {
        char[] nonceChars = new char[6];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS2.charAt(RANDOM.nextInt(SYMBOLS2.length()));
        }
        return new String(nonceChars);
    }

    public static byte[] readInput(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
        out.close();
        in.close();
        return out.toByteArray();
    }


}

